package model.userhandler;

import java.io.Serializable;
import model.information.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Observable;

/**
 * A class that keeps track of all the information objects in the application.
 * @author Tobias Møller Kjærsgaard
 * @author Hjalte Blichfeldt Flyger
 * @author Gitte Simonsen
 * @author Claus Lund
 */
public class InformationManager extends Observable implements Serializable{
    private ArrayList<Contact> contacts;
    private ArrayList<Event> events;
    private ArrayList<JournalEntry> journal;
    private ArrayList<Link> links;
    private ArrayList<Memo> memos;
    private ArrayList<Password> passwords;
    private ArrayList<Research> researchnotes;
    private ArrayList<Meal> meals;
    private ArrayList<Workout> workouts;

    /**
     * Constructor that creates empty ArrayLists for each class in the information package.
     */
    public InformationManager() {
        contacts = new ArrayList<Contact>();
        events = new ArrayList<Event>();
        journal = new ArrayList<JournalEntry>();
        links = new ArrayList<Link>();
        memos = new ArrayList<Memo>();
        passwords = new ArrayList<Password>();
        researchnotes = new ArrayList<Research>();
        meals = new ArrayList<Meal>();
        workouts = new ArrayList<Workout>();
    }

////////////////// Add/remove methods for each ArrayList: //////////////////
    public void addContact(Contact o) {
        contacts.add(o);
        setChanged();
        notifyObservers("contacts");
    }

    public void removeContact(Contact o) {
        contacts.remove(o);
        setChanged();
        notifyObservers("contacts");
    }

    public void addEvent(Event o) {
        events.add(o);
        setChanged();
        notifyObservers("events");
    }

    public void removeEvent(Event o) {
        events.remove(o);
        setChanged();
        notifyObservers("events");
    }

    public void addJournalEntry(JournalEntry o) {
        journal.add(o);
        setChanged();
        notifyObservers("journal");
    }

    public void removeJournalEntry(JournalEntry o) {
        journal.remove(o);
        setChanged();
        notifyObservers("journal");
    }

    public void addLink(Link o) {
        links.add(o);
        setChanged();
        notifyObservers("links");
    }

    public void removeLink(Link o) {
        links.remove(o);
        setChanged();
        notifyObservers("links");
    }

    public void addMemo(Memo o) {
        memos.add(o);
        setChanged();
        notifyObservers("memos");
    }

    public void removeMemo(Memo o) {
        memos.remove(o);
        setChanged();
        notifyObservers("memos");
    }

    public void addPassword(Password o) {
        passwords.add(o);
        setChanged();
        notifyObservers("passwords");
    }

    public void removePassword(Password o) {
        passwords.remove(o);
        setChanged();
        notifyObservers("passwords");
    }

    public void addResearch(Research o) {
        researchnotes.add(o);
        setChanged();
        notifyObservers("researchnotes");
    }

    public void removeResearch(Research o) {
        researchnotes.remove(o);
        setChanged();
        notifyObservers("researchnotes");
    }

    public void addMeal(Meal o) {
        meals.add(o);
        setChanged();
        notifyObservers("meals");
    }

    public void removeMeal(Meal o) {
        meals.remove(o);
        setChanged();
        notifyObservers("meals");
    }

    public void addWorkout(Workout o) {
        workouts.add(o);
        setChanged();
        notifyObservers("workouts");
    }

    public void removeWorkout(Workout o) {
        workouts.remove(o);
        setChanged();
        notifyObservers("workouts");
    }

////////////////// Getters for each ArrayList: //////////////////
    public ArrayList<Contact> getContacts() {
        return contacts;
    }

    public ArrayList<Event> getEvents() {
        return events;
    }

    public ArrayList<JournalEntry> getJournal() {
        return journal;
    }

    public ArrayList<Link> getLinks() {
        return links;
    }

    public ArrayList<Memo> getMemos() {
        return memos;
    }

    public ArrayList<Password> getPasswords() {
        return passwords;
    }

    public ArrayList<Research> getResearchnotes() {
        return researchnotes;
    }

    public ArrayList<Meal> getMeals() {
        return meals;
    }

    public ArrayList<Workout> getWorkouts() {
        return workouts;
    }

////////////////// Remaining methods: //////////////////
    /**
     * Itterates the events-list and removes all entries with a startDate prior to the date argument.
     * @param date a Calendar object that defines the date before which the events should be removed.
     * @return the number of events removed.
     */
    public int removeOldEvents(Calendar date) {
        int counter = 0;
        Iterator it = events.iterator();
        while(it.hasNext()) {
            Event e = (Event)it.next();
            if(e.getStartTime().before(date)) {
                it.remove();
                counter++;
            }
        }
        setChanged();
        notifyObservers("events");
        return counter;
    }

    /**
     * Itterates the memos-list and removes all entries with a startDate prior to the date argument.
     * @param date a Calendar object that defines the date before which the memos should be removed.
     * @return the number of memos removed.
     */
    public int removeOldMemos(Calendar date) {
        int counter = 0;
        Iterator it = memos.iterator();
        while(it.hasNext()) {
            Memo m = (Memo)it.next();
            if(m.getDate().before(date)) {
                it.remove();
                counter++;
            }
        }
        setChanged();
        notifyObservers("memos");
        return counter;
    }

    /**
     * Sorts all events by start date.
     */
    public void sortEvents() {
        Comparator eventComparator = new Comparator() {
            public int compare(Object o1, Object o2) {
                Event e1 = (Event)o1;
                Event e2 = (Event)o2;
                long t1 = e1.getStartTime().getTimeInMillis();
                long t2 = e2.getStartTime().getTimeInMillis();
                
                if(t1 == t2) {
                    return 0;
                } else if (t1 < t2) {
                    return -1;
                } else {
                    return 1;
                }
            }
        };
        
        Collections.sort(events, eventComparator);
        setChanged();
        notifyObservers("events");
    }

    /**
     * Sorts all contacts alphabetically by firstname.
     */
    public void sortContacts() {
        Comparator contactComparator = new Comparator() {
            public int compare(Object o1, Object o2) {
                Contact c1 = (Contact)o1;
                Contact c2 = (Contact)o2;
                String n1 = c1.getFirstName();
                String n2 = c2.getFirstName();

                Comparator nameComparator = String.CASE_INSENSITIVE_ORDER;

                return nameComparator.compare(n1, n2);
            }
        };

        Collections.sort(contacts, contactComparator);
        setChanged();
        notifyObservers("contacts");
    }

    
    public int calcMealTotalProt() {
        int value = 0;
        for(Meal m: meals) {
            value += m.calcTotalProt();
        }
        return value;
    }

    public int calcMealTotalCar() {
        int value = 0;
        for(Meal m: meals) {
            value += m.calcTotalCar();
        }
        return value;
    }

    public int calcMealTotalFat() {
        int value = 0;
        for(Meal m: meals) {
            value += m.calcTotalFat();
        }
        return value;
    }

    public int calcMealTotalKcal() {
        int value = 0;
        for(Meal m: meals) {
            value += m.calcTotalKcal();
        }
        return value;
    }

    @Override
    public String toString() {
        return "iManager";
    }


}